#include <iostream>

#include "wifi_board.h"
#include "display/lcd_display.h"
#include "system_reset.h"
#include "application.h"
#include "button.h"
#include "config.h"
#include "iot/thing_manager.h"
#include "led/single_led.h"
#include "no_audio_codec.h"

#include <esp_log.h>
#include <driver/ledc.h>
#include <wifi_station.h>
#include <esp_lcd_panel_io.h>
#include <esp_lcd_panel_ops.h>
#include <esp_lcd_spd2010.h>
#include <esp_timer.h>
#include "esp_io_expander_tca9554.h"
#include <iot_button.h>


#define TAG "my_borad"

LV_FONT_DECLARE(font_puhui_16_4);
LV_FONT_DECLARE(font_awesome_16_4);


class ATKDNESP32S3MBoard : public WifiBoard {
public:
    ATKDNESP32S3MBoard() {
        InitializeButtons();
        InitializeSpi();
        InitializeSt7735Display();
    }
    ~ATKDNESP32S3MBoard() {
        delete led_;
        delete display_;
        delete button_;
    }

    virtual Led* GetLed() override {
        led_ = new SingleLed(LED_PIN);
        return led_;
    }

    virtual Display* GetDisplay() override {
        return display_;
    }

    virtual AudioCodec* GetAudioCodec() override { 
        static NoAudioCodec codec_;
        return &codec_;

    }

private:
    static SingleLed *led_;
    static SpiLcdDisplay *display_;
    static Button* button_;


        // Initialize spi peripheral
    void InitializeSpi() {
            // 重置引脚状态
        gpio_reset_pin(QSPI_PIN_NUM_LCD_MOSI);
        gpio_reset_pin(QSPI_PIN_NUM_LCD_PCLK);
        spi_bus_config_t buscfg = {};
        buscfg.mosi_io_num = QSPI_PIN_NUM_LCD_MOSI;
        buscfg.miso_io_num = GPIO_NUM_NC;
        buscfg.sclk_io_num = QSPI_PIN_NUM_LCD_PCLK;
        buscfg.quadwp_io_num = GPIO_NUM_NC;
        buscfg.quadhd_io_num = GPIO_NUM_NC;
        buscfg.max_transfer_sz = DISPLAY_WIDTH * DISPLAY_HEIGHT * sizeof(uint16_t);
        ESP_LOGD(TAG, "Initialize SPI bus");
        ESP_ERROR_CHECK(spi_bus_initialize(QSPI_LCD_HOST, &buscfg, SPI_DMA_CH_AUTO));
    }

    void InitializeSt7735Display() {
        esp_lcd_panel_io_handle_t panel_io = nullptr;
        esp_lcd_panel_handle_t panel = nullptr;
        // 液晶屏控制IO初始化
        ESP_LOGD(TAG, "Install panel IO");
        esp_lcd_panel_io_spi_config_t io_config = {};
        io_config.cs_gpio_num = QSPI_PIN_NUM_LCD_CS;
        io_config.dc_gpio_num = QSPI_PIN_NUM_LCD_MOSI;
        io_config.spi_mode = 0;
        io_config.pclk_hz = 60 * 1000 * 1000;
        io_config.trans_queue_depth = 7;
        io_config.lcd_cmd_bits = 8;
        io_config.lcd_param_bits = 8;
        ESP_ERROR_CHECK(esp_lcd_new_panel_io_spi(QSPI_LCD_HOST, &io_config, &panel_io));

        // 初始化液晶屏驱动芯片
        ESP_LOGD(TAG, "Install LCD driver");
        esp_lcd_panel_dev_config_t panel_config = {};
        panel_config.reset_gpio_num = QSPI_PIN_NUM_LCD_RST;
        panel_config.rgb_ele_order = LCD_RGB_ELEMENT_ORDER_BGR;
        panel_config.bits_per_pixel = 16;
        panel_config.data_endian = LCD_RGB_DATA_ENDIAN_BIG;
        ESP_ERROR_CHECK(esp_lcd_new_panel_st7789(panel_io, &panel_config, &panel));

        esp_lcd_panel_reset(panel);
        esp_lcd_panel_init(panel);

        uint8_t data0[] = {0x02, 0x1c, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2d, 0x29, 0x25, 0x2B, 0x39, 0x00, 0x01, 0x03, 0x10};
        uint8_t data1[] = {0x03, 0x1d, 0x07, 0x06, 0x2E, 0x2C, 0x29, 0x2D, 0x2E, 0x2E, 0x37, 0x3F, 0x00, 0x00, 0x02, 0x10};
        esp_lcd_panel_io_tx_param(panel_io, 0xe0, data0, 16);
        esp_lcd_panel_io_tx_param(panel_io, 0xe1, data1, 16);

        esp_lcd_panel_invert_color(panel, true);
        esp_lcd_panel_swap_xy(panel, DISPLAY_SWAP_XY); 
        esp_lcd_panel_mirror(panel, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y);

        display_ = new SpiLcdDisplay(panel_io, panel,
                                    DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_OFFSET_X, DISPLAY_OFFSET_Y, DISPLAY_MIRROR_X, DISPLAY_MIRROR_Y, DISPLAY_SWAP_XY,
                                    {
                                        .text_font = &font_puhui_16_4,
                                        .icon_font = &font_awesome_16_4,
                                        .emoji_font = font_emoji_32_init(),
                                    });
    }

    void push_button_cb() {
        ESP_LOGI(TAG, "button push");
        display_->SetEmotion("sad");
    }

    void InitializeButtons() {
        button_ = new Button(BUTTON_PIN_NUM, 0);
        button_->OnPressDown([this]() {
            this->push_button_cb();
        });
    }
};

DECLARE_BOARD(ATKDNESP32S3MBoard);

SingleLed *ATKDNESP32S3MBoard::led_ = nullptr;
SpiLcdDisplay *ATKDNESP32S3MBoard::display_ = nullptr;
Button* ATKDNESP32S3MBoard::button_ = nullptr;
